/*
    WVEFILE.C

Sound record/playback sound file
*/

#include <p_std.h>
#include <p_gen.h>
#include <p_que.h>
#include <p_object.h>
#include <p_file.h>
#include <wlib.h>
#include <hwim.h>
#include <record.g>

LOCAL_C ULONG SamplesToTenths(ULONG samples)
    {
    return((samples>>4)/50);
    }

LOCAL_C ULONG EffectiveSamples(ULONG samples)
/*
Converts the number of byte samples to the effective number of
samples for playback by rounding up to the nearest 0x800 (2K)
boundary and adding another 0x600.
*/
    {
    return(((samples+0x7ff)&(~0x7ff))+0x600);
    }

LOCAL_C VOID CloseFile(PR_WVEFILE *self)
    {
    p_close(self->wvefile.fcb);
    self->wvefile.fcb=NULL;
    }

LOCAL_C VOID StoreFileName(PR_WVEFILE *self,TEXT *fname)
    {
    CloseFile(self);
    f_fparse(fname,NULL,&self->wvefile.fname[0],&self->wvefile.crk);
    hEnsurePath(&self->wvefile.fname[0]);
    }

#pragma METHOD_CALL


METHOD INT wvefile_wve_new(PR_WVEFILE *self,TEXT *fname)
/*
Return the maximum duration in seconds consistent with the space on fspec
as a positive number. Otherwise return a negative error number.
*/
    {
    UINT minfree;
    INT SSDType;
    P_DINFO dinfo;

    StoreFileName(self,fname);
    p_dinfo(&self->wvefile.fname[0],&dinfo);
    minfree=0x1000; /* need at least approx half a seconds worth of space */
    SSDType=dinfo.mediatype&0xff;
    if (SSDType==P_FMEDIA_FLASH)
        return(E_FILE_VOLUME);
    if (SSDType==P_FMEDIA_ROM || SSDType==P_FMEDIA_WRITEPROTECTED)
        return(E_FILE_PROTECT);
    if (dinfo.mediatype&P_FMEDIA_INTERNAL)
        minfree+=0x2800; /* since the sound server takes 0x2800 bytes to run */
    if (p_finfo(&self->wvefile.fname[0],&self->wvefile.info)>=0)
        {
        if (!(self->wvefile.info.status&P_FAWRITE))
            return(E_FILE_RDONLY);
        dinfo.free+=self->wvefile.info.size; /* credit length of existing file */
        }
    if (dinfo.free<minfree)
        return(0);
    return((UINT)(SamplesToTenths(dinfo.free-minfree)/10));
    }

METHOD VOID wvefile_wve_open(PR_WVEFILE *self,TEXT *fname)
/*
If fname is NULL, attempt to open the stored file name.
Otherwise, attempt to open name.
*/
    {
    if (fname)
        StoreFileName(self,fname);
    self->wvefile.ret=p_finfo(&self->wvefile.fname[0],&self->wvefile.info);
    if (self->wvefile.ret<0)
        return;
    CloseFile(self); /* file can be open after an error in playback */
    self->wvefile.ret=p_open(&self->wvefile.fcb,&self->wvefile.fname[0],P_FSHARE);
    if (self->wvefile.ret<0)
        return;
    self->wvefile.ret=p_read(self->wvefile.fcb,&self->wvefile.head,sizeof(SndFile));
    if (self->wvefile.ret<0)
        {
    close:
        CloseFile(self);
        return;
        }
    if (p_scmp(&self->wvefile.head.Signature[0],ALawSignature))
        {
        self->wvefile.ret=E_FILE_INVALID;
        goto close;
        }
    /* Wany "bootleg" files exist with incorrect Samples field */
    /* The sound system services work off the file length and not Samples */
    /* So we patch Samples here to the correct value */
    self->wvefile.head.Samples=self->wvefile.info.size-sizeof(SndFile);
    if (self->wvefile.head.Repeats==0)
        self->wvefile.head.Repeats=1;
    }

METHOD TEXT *wvefile_wve_sense_fname(PR_WVEFILE *self)
    {
    return(&self->wvefile.fname[0]);
    }

METHOD VOID wvefile_wve_sense_info(PR_WVEFILE *self,WVEFILE_INFO *pi)
/*
Write all kinds of information to *pi.
*/
    {
    ULONG samples;

    p_bfil(pi,sizeof(WVEFILE_INFO),0);
    pi->device=&self->wvefile.fname[self->wvefile.crk.system];
    pi->name=pi->device+self->wvefile.crk.device+self->wvefile.crk.path;
    pi->nmlen=self->wvefile.crk.name;
    if (self->wvefile.fcb==NULL)
        return;
    pi->duration=SamplesToTenths(self->wvefile.head.Samples);
    pi->silence=(WORD)(((ULONG)self->wvefile.head.SilenceInTicks*5)>>4);
    samples=EffectiveSamples(self->wvefile.head.Samples);
    samples+=250*(ULONG)self->wvefile.head.SilenceInTicks; /* 250 samples per tick */
    if (self->wvefile.head.Repeats>1 && self->wvefile.head.SilenceInTicks<2)
        samples+=500; /* the minimum silence between repeats */
    pi->repeats=self->wvefile.head.Repeats;
    pi->total=SamplesToTenths(samples*pi->repeats);
    pi->samples=self->wvefile.head.Samples;
    pi->flen=self->wvefile.info.size;
    }

METHOD VOID wvefile_wve_set_repeats(PR_WVEFILE *self,UINT repeats,UINT tenths)
/*
If repeats is zero or more, set the number of repeats and the trailing silence
to tenths in 1/10s of a second.
If repeats is zero, set the silence such that the total duration with the
current number of repeats is equal to tenths.
*/
    {
    INT ret;
    INT silence,maxrepeats;
    LONG total,period;

    ret=0;
    if (self->wvefile.fcb==NULL)
        return;
    if (repeats>0)
        silence=(INT)(((ULONG)tenths<<4)/5); /* convert to ticks */
    else
        { /* tenths is total desired time */
        repeats=self->wvefile.head.Repeats;
        total=tenths;
        total*=800; /* convert tenths to samples */
        period=EffectiveSamples(self->wvefile.head.Samples);
        maxrepeats=(INT)(total/(period+500));
        if (repeats<2 || repeats>maxrepeats)
            repeats=maxrepeats;
        if (repeats==0)
            repeats=1;
        silence=0;
        if (repeats>1)
            silence=(INT)((total-repeats*period+249*repeats)/(250*repeats));
        }
    if (silence==self->wvefile.head.SilenceInTicks && repeats==self->wvefile.head.Repeats)
        return; /* no change */
    self->wvefile.head.SilenceInTicks=silence;
    self->wvefile.head.Repeats=repeats;
    CloseFile(self);
    ret=p_open(&self->wvefile.fcb,&self->wvefile.fname[0],P_FUPDATE);
    if (ret>=0)
        {
        ret=p_write(self->wvefile.fcb,&self->wvefile.head,sizeof(SndFile));
        CloseFile(self);
        }
    wvefile_wve_open(self,NULL);
    f_leave(ret);
    }


